package com.momo.hrmailserver.receiver;

import com.momo.hr.bean.Employee;
import com.momo.hr.bean.MailConstants;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.util.Date;

@Component
public class MailReceiver {

    public static final Logger logger = LoggerFactory.getLogger(MailReceiver.class);

    @Autowired
    JavaMailSender javaMailSender;

    @Autowired
    MailProperties mailProperties;

    @Autowired
    TemplateEngine templateEngine;

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 这里是监听的队列消息的Biz
     * @param message Spring整合JMS中的消息 对象
     * @param channel RabbitMQ的通信包，是Rabbit的一个“管道” 网路信道路，几乎所有的操作都会在Channel中进行。
     */
    @SuppressWarnings("unchecked")
    @RabbitListener(queues = MailConstants.MAIL_QUEUE_NAME)
    public void handler(Message message, Channel channel) {
        /* 从这里开始是消息的幂等性检查 */
        Employee employee = (Employee) message.getPayload();//从JMS发送的消息中获取到Service发送的Employee对象
        MessageHeaders headers = message.getHeaders();//获得消息头部信息
        Long tag = (Long)headers.get(AmqpHeaders.DELIVERY_TAG);//在消息通道中额唯一 标识，通过他来确认收到消息
        String msgId = (String) headers.get("spring_returned_message_correlation");
        if(redisTemplate.opsForHash().entries("mail_log").containsKey(msgId)){
            //redis中含有这个Key，说明已经被消费过了
            logger.info(msgId+"消息已经被消费");
            try {
                channel.basicAck(tag,false);//告诉RabbitMQ 这个消息已经被确认了，不需要消费了
            } catch (IOException e) {
                e.printStackTrace();
            }
            /* 如果消息已经被消费过了、那么就直接结束发送， */
            return;
        }
        logger.info(employee.toString());
        //收到消息,发送邮件
        MimeMessage mimeMessage = null;
        try {
        mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage);
        mimeMessageHelper.setFrom(mailProperties.getUsername());//设置密码
        mimeMessageHelper.setTo(employee.getEmail());//发送地址
        mimeMessageHelper.setSubject("入职offer");//设置邮件主题
        mimeMessageHelper.setSentDate(new Date());//设置发送时间
        Context context = new Context();//设置内容跟上下文
        context.setVariable("nickname",employee.getName());
        context.setVariable("posName",employee.getPosition().getName());
        context.setVariable("jobName",employee.getJobLevel().getName());
        context.setVariable("departName",employee.getDepartment().getName());
        String mail = templateEngine.process("mail", context);//设置完成以后
        mimeMessageHelper.setText(mail,true);//后面的布尔值确定这个是否是Html文件
            //发送邮件
        javaMailSender.send(mimeMessage);
        logger.debug("邮件发送成功");
            try {
                channel.basicAck(tag,false);//告诉RabbitMQ 这个消息已经被确认了，不需要消费了
                //然后我们在Redis中去添加一个属性，是的不在需要发送这条消息。
                redisTemplate.opsForHash().put("mail_log",msgId,"momo");
            } catch (IOException e) {
                e.printStackTrace();
                logger.debug("邮件发送成功");
            }
        } catch (MessagingException e) {
            //如果发送失败的话
            try {
                channel.basicNack(tag,false,true);//我们让这条消息重新回到队列，等待下一次消费
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
            e.printStackTrace();
        }

    }
}
